/*
    backend for TimeTagger, an OpalKelly based single photon counting library
    Copyright (C) 2011  Markus Wick <wickmarkus@web.de>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "Histogram.h"
#include <sstream>

#include "Logger.h"
DECLARE_LOG_SUPPORT(MODULES)

Histogram::Histogram(int chan, int chan2, long long binwidth) {
	debug("Histogram created.");
	channel  = chan;
	channel2 = (chan2==-1)?chan:chan2;
	this->binwidth = binwidth;
	registerChannel(channel);
	registerChannel(channel2);
	clear();
	start();
}

Histogram::~Histogram() {
	stop();
}

const char *Histogram::getClassName() {
	return "Histogram";
}

const char * Histogram::getScpiCommand() {
	return ":CONFigure:HISTogram";
}

std::string Histogram::getScpiParameters() {
	std::stringstream ss;
	ss << "chan" << channel << ",chan" << channel2 << ',' << binwidth;
	return ss.str();
}

void Histogram::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {
	const int sz=4;
	long long *arr = new long long[sz];

	synchronized(*this) {
		long long *ptr=arr;
		*ptr++=channel;
		*ptr++=channel2;
		*ptr++=binwidth;
		*ptr++=last;
	}

	*ARGOUTVIEWM_ARRAY2 = arr;
	*DIM1 = sz;
}

void Histogram::start() {
	lock();
	last = 0;
	unlock();
	_Iterator::start();
}

void Histogram::getData(long long **ARGOUTVIEWM_ARRAY2, int *DIM1, int *DIM2) {
	lock();
	int s = data.size();
	long long *arr = new long long[s*2];
	std::map<long long,long long>::iterator it;
	int i=0;

	for ( it=data.begin() ; it != data.end(); it++ ) {
		arr[i++] = it->first*binwidth;
		arr[i++] = it->second;
	}

	*ARGOUTVIEWM_ARRAY2 = arr;
	*DIM1 = s;
	*DIM2 = 2;
	unlock();
}

void Histogram::clear() {
	lock();
	last = 0;
	data = std::map<long long,long long>();
	unlock();
}

void Histogram::next(Tag* list, int count, long long time) {
	for(int i = 0; i < count; i++) {
		if(list[i].overflow) {
			last = 0;
		} else if(list[i].chan == channel && last != 0) {
			data[(list[i].time - last)/binwidth] += 1;
			if(channel == channel2)
				last = list[i].time;
			else
				last = 0;
		} else if(list[i].chan == channel2)
			last = list[i].time;
	}
}


Distribution::Distribution(int chan, int _divisor) {
	debug("Distribution created.");
	channel = chan;
	divisor = _divisor;
	if(divisor < 1) divisor = 1;
	counts = new long long[picosecounds/divisor];
	registerChannel(chan);
	clear();
	start();
}
        
Distribution::~Distribution() {
	stop();
	delete [] counts;
}

const char *Distribution::getClassName() {
	return "Distribution";
}

const char * Distribution::getScpiCommand() {
	return ":CONFigure:DISTribution";
}

std::string Distribution::getScpiParameters() {
	std::stringstream ss;
	ss << "chan" << channel << ',' << divisor;
	return ss.str();
}

void Distribution::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {
	const int sz=2;
	long long *arr = new long long[sz];

	synchronized(*this) {
		long long *ptr=arr;
		*ptr++=channel;
		*ptr++=divisor;
	}

	*ARGOUTVIEWM_ARRAY2 = arr;
	*DIM1 = sz;
}

void Distribution::getData(long long **ARGOUTVIEWM_ARRAY1, int *DIM1) {
		lock();
		long long *arr = new long long[picosecounds/divisor];

		for ( int i=0; i<picosecounds/divisor; i++ )
				arr[i] = counts[i];

		*ARGOUTVIEWM_ARRAY1 = arr;
		*DIM1 = picosecounds/divisor;
		unlock();
}

void Distribution::clear() {
		lock();
		for(int i=0; i<picosecounds/divisor; i++)
				counts[i]=0;
		unlock();
}

void Distribution::next (Tag *list, int count, long long time) {
		for(int i = 0; i < count; i++) {
				if(list[i].chan == channel) {
						counts[(list[i].time%picosecounds)/divisor]++;
				}
		}
}
